#include "SignatureHelper.h"
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <sstream>
#include <iomanip>
#include <cstring>
#include <chrono>

namespace MessageFramework {

// ==================== 私有辅助函数 ====================

std::string SignatureHelper::hmacSha256(const std::string& data, const std::string& key) {
    unsigned char hash[EVP_MAX_MD_SIZE];
    unsigned int hashLen = 0;

    HMAC(EVP_sha256(),
         key.c_str(), static_cast<int>(key.size()),
         reinterpret_cast<const unsigned char*>(data.c_str()), data.size(),
         hash, &hashLen);

    // 转换为Hex字符串
    std::ostringstream oss;
    for (unsigned int i = 0; i < hashLen; ++i) {
        oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
    }
    return oss.str();
}

std::string SignatureHelper::sha256(const std::string& data) {
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256(reinterpret_cast<const unsigned char*>(data.c_str()), data.size(), hash);

    // 转换为Hex字符串
    std::ostringstream oss;
    for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
        oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
    }
    return oss.str();
}

std::string SignatureHelper::serializeHeaderForSignature(const MessageHeader& header) {
    // 序列化除signature外的所有字段
    std::ostringstream oss;
    oss << "{"
        << "\"messageId\":\"" << header.messageId << "\","
        << "\"messageType\":\"" << header.messageType << "\","
        << "\"version\":\"" << header.version << "\","
        << "\"publisherId\":\"" << header.publisherId << "\","
        << "\"consumerId\":\"" << header.consumerId << "\","
        << "\"targetStream\":\"" << header.targetStream << "\","
        << "\"replyStream\":\"" << header.replyStream << "\","
        << "\"timestamp\":" << header.timestamp << ","
        << "\"expiresAt\":" << header.expiresAt << ","
        // 注意：这里不包含signature字段
        << "\"encrypted\":" << (header.encrypted ? "true" : "false") << ","
        << "\"encryptionAlgo\":\"" << header.encryptionAlgo << "\","
        << "\"traceId\":\"" << header.traceId << "\","
        << "\"parentId\":\"" << header.parentId << "\","
        << "\"priority\":" << header.priority << ","
        << "\"contentLength\":" << header.contentLength << ","
        << "\"contentType\":\"" << header.contentType << "\""
        << "}";
    return oss.str();
}

// ==================== 公共接口 ====================

std::string SignatureHelper::hashBody(const std::string& body) {
    return sha256(body);
}

std::string SignatureHelper::generatePayload(const MessageHeader& header, const std::string& bodyHash) {
    std::string headerStr = serializeHeaderForSignature(header);
    return headerStr + "|" + bodyHash;
}

std::string SignatureHelper::sign(MessageHeader& header, const std::string& body, const std::string& secretKey) {
    // 1. 计算Body的SHA256哈希
    std::string bodyHash = hashBody(body);

    // 2. 生成签名载荷
    std::string payload = generatePayload(header, bodyHash);

    // 3. 计算HMAC-SHA256签名
    std::string signature = hmacSha256(payload, secretKey);

    // 4. 填充到header的signature字段
    std::strncpy(header.signature, signature.c_str(), sizeof(header.signature) - 1);
    header.signature[sizeof(header.signature) - 1] = '\0';  // 确保null终止

    return signature;
}

bool SignatureHelper::verify(const MessageHeader& header, const std::string& body,
                             const std::string& secretKey, int timeWindowSeconds) {
    // 1. 时间窗口验证（防重放攻击）
    if (timeWindowSeconds > 0) {
        auto now = std::chrono::high_resolution_clock::now();
        int64_t currentTimestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
            now.time_since_epoch()).count();

        int64_t age = (currentTimestamp - header.timestamp) / 1000000000LL;  // 转换为秒

        if (std::abs(age) > timeWindowSeconds) {
            // 消息超出时间窗口
            return false;
        }
    }

    // 2. 重新计算期望的签名
    std::string bodyHash = hashBody(body);
    std::string payload = generatePayload(header, bodyHash);
    std::string expectedSignature = hmacSha256(payload, secretKey);

    // 3. 对比签名（常量时间比较，防时序攻击）
    if (expectedSignature.length() != std::strlen(header.signature)) {
        return false;
    }

    // 使用constant-time比较防止时序攻击
    int result = 0;
    for (size_t i = 0; i < expectedSignature.length(); ++i) {
        result |= (expectedSignature[i] ^ header.signature[i]);
    }

    return result == 0;
}

} // namespace MessageFramework
